﻿using StackExchange.Redis.Extensions.MQ;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using StackExchange.Redis.Extensions.Lock;
using System.Threading.Tasks;
using StackExchange.Redis.Extensions.SlidingWindow;
using Newtonsoft.Json;
using StackExchange.Redis.Extensions.CacheManager;

namespace RedisLibImple.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CacheManagerController : ControllerBase
    {
        private readonly ILogger<CacheManagerController> _logger;
        private readonly IConnectionMultiplexer _connection;

        public CacheManagerController(ILogger<CacheManagerController> logger, IConnectionMultiplexer connection)
        {
            _logger = logger;
            _connection = connection;
        }

        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new List<string>() { "Hello World" };
        }

        [HttpGet("lock")]
        public string lockString()
        {
            var task1 = Task.Run(() => {
                var stringObject = _connection.GetDatabase(2).DistributionLock<String>("TriggerDelayedSyncAsync", 10, (key) => 
                {
                    _logger.LogInformation("key => " + key);
                    return new String("value"); 
                });

                if (stringObject != null && stringObject.Equals("value"))
                {
                    _logger.LogInformation("OK -> Task1");
                }
            });

            var task2 = Task.Run(() => {
                var stringObject = _connection.GetDatabase(2).DistributionLock<String>("TriggerDelayedSyncAsync", 10, (key) => 
                {
                    //System.Threading.Thread.Sleep(40000);
                    return new String("value"); 
                });
                if (stringObject != null && stringObject.Equals("value"))
                {
                    _logger.LogInformation("OK -> Task2");
                }
            });

            Task.WaitAll(task1, task2);
            
            return "Ok";
        }

        [HttpGet("push/{value}")]
        public string pushMessage(string value)
        {
            var index = _connection.GetDatabase().PushMessage(value);

            return index.ToString();
        }

        [HttpGet("pop")]
        public string popMessage()
        {
            var deploymentId = Guid.NewGuid().ToString();

            var task1 = Task.Run(() => {
                var stringObject = _connection.GetDatabase().PopMessage<String>(deploymentId, (key) =>
                {
                    return new String(key);
                });
                if (stringObject != null)
                {
                    _logger.LogInformation(stringObject);
                }
            });
            var task2 = Task.Run(() => {
                var stringObject = _connection.GetDatabase().PopMessage<String>(deploymentId, (key) =>
                {
                    return new String(key);
                });
                if (stringObject != null )
                {
                    _logger.LogInformation(stringObject);
                }
            });

            Task.WaitAll(task1, task2);

            return "Ok";
        }

        [HttpGet("window/keys/{key}")]
        public string SlidingWindow(string key)
        {
            var score = _connection.GetDatabase(4).SetKey(key);
            
            return score.ToString();
        }

        [HttpGet("window/topKeys/{topKey}")]
        public string TopSlidingWindow(int topKey)
        {
            var deploymentId = Guid.NewGuid().ToString();

            var scores = _connection.GetDatabase(4).GetTopKeys(topKey, 10);

            return JsonConvert.SerializeObject(scores);
        }

        [HttpGet("window/keys/{key}/scores/{source}")]
        public string ReleaseSlidingWindow(string key, double source)
        {
            var deploymentId = Guid.NewGuid().ToString();

            var isSuccessed = _connection.GetDatabase(4).SetRemoveWithScore(key, source);

            return isSuccessed.ToString();
        }

        [HttpPost("cache/add/{key}")]
        public string AddCache(string key, PostCache cache)
        {
            var isSuccessed = _connection.GetDatabase().Add<PostCache>(key, cache);

            return isSuccessed.ToString();
        }

        [HttpGet("cache/get/{key}")]
        public string GetCache(string key)
        {
            var cache = _connection.GetDatabase().Get<PostCache>(key);

            return JsonConvert.SerializeObject(cache);
        }

        [HttpPost("cache/set/{key}")]
        public string SetCache(string key, PostCache cache)
        {
            var isSuccessed = _connection.GetDatabase().Set<PostCache>(key, cache);

            return isSuccessed.ToString();
        }

        [HttpDelete("cache/delete/{key}")]
        public string DeleteCache(string key)
        {
            var isSuccessed = _connection.GetDatabase().Delete(key);

            return isSuccessed.ToString();
        }

        [HttpDelete("cache/deleteAll/{key}")]
        public string DeleteAllCache(string key)
        {
            var keys = _connection.GetDatabase().GetAll(key);

            foreach(var key1 in keys)
            {
                _connection.GetDatabase().Delete(key1);
            }

            return "Success";
        }
    }

    public class PostCache
    {
        public string Id { get; set; }

        public string Name { get; set; }

        public string Sex { get; set; }
    }
}
